#ifndef ENGINE_H
#define ENGINE_H

#include <string>
#include <set>
#include <list>
#include <iostream>
#include <queue>
#include <cassert>
#include "BrainSwitch.h"
#include "Watch.h"
#include "ChildrenNode.h"
#include "Types.h"
#include "Position.h"
#include "thread.h"
using namespace std;



class Engine
{
public:
	Engine(void);
	void init();
	~Engine(void);

	Position currPos;
	BrainStatus brainStatus;
	BrainMode brainMode;
	bool debugMode;
	bool isSmartTiming;
	long thinkDelay;
	int depthLevel;
	int nodeMaxNumber;
	bool isVerbose;
	int maxDepth;
	long wtime; //total time left for white in millisec
    long btime; //total time left for black in millisec
    long winc;
    long binc;
	int processedNodes;
	queue<ChildrenNode> nodeQueue;
	Lock nodeQueueLock;
	//CTMultiThreadSingleQueue<Node> nodeQueue;
	list<ChildrenNode> possibleNodes; // Nodes for possible moves

	//ThreadsManager threads;
	// TODO: use only one watch !!!
	Watch watch;
	
	void SetStartPosition();
	void SetPosition(const std::string& fen);
	void SetPonderLimit(bool ponder);
	bool IsStopOnPonderHit();
	Move* GetBestMove();

	void FlipBoard();
	void ReadEvaluation();
	void TraceEvaluate();
	char* GetEngineInfo();
	char* GetEngineOptions();
	//void DoMove(Move m, StateInfo& state);
	bool IsValidOption(string name);
	void SetOption(string name, string value);
	void SetLimitsInfinite(bool b);
	void SetLimitsPonder(bool b);
	void Start();
	void Stop();
	void Quit();
	void SetDebug(bool isDebugOn);
	void Bench(string part);
	void Test(string part);
	void SetSmartTiming(bool value);

public:
	void GetCpuInfo();

public: // Test part
	void TestGetLegalMoves();
	bool IsEqual(list<Move>& moveList1, string& moveList2);

public: // Bench part
	void BenchThreadManager();
	void BenchGetLegalMoves();
	void BenchGetPossibleMoves();

	void DisplayMoves(list<Move>& moveList);
	void UpdateThinkDelay();

	//int InjectNodes();
	void SetVerboseMode(bool isVerboseMode);
	void UpdatePossibleNodesScores(int maxDepth);
	void DisplayBestPve(int maxDepth);
	ChildrenNode* GetBestNode();
	ChildrenNode* GetMinNode(list<ChildrenNode>& possibleNodes);
	ChildrenNode* GetMaxNode(list<ChildrenNode>& possibleNodes);
	ChildrenNode* GetMinNode(list<ChildrenNode*>* possibleNodes);
	ChildrenNode* GetMaxNode(list<ChildrenNode*>* possibleNodes);


	void NodeInjectorThreadLoopMultithreads();
	void InitPossibleNodes(list<Move>& moves);

};

//For global access
extern Engine ChessEngine;


#endif